package org.liang.job.impl;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobKey.jobKey;
import static org.quartz.TriggerKey.triggerKey;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.liang.job.common.IDBuilder.buildUniqueID;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.liang.job.SchedulerUpdater;
import org.liang.job.beans.Cron;
import org.liang.job.beans.Job;
import org.liang.job.common.JobConstant;
import org.liang.job.core.BaseJob;
import org.liang.job.repository.SchedulerUpdateRepository;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 任务计划服务实现类.
 *
 * @author L.Yang
 * @version 1.0, 2015年9月24日
 */
@Service("schedulerUpdater")
public class SchedulerUpdaterImpl implements SchedulerUpdater {

    /** 日志对象. */
    private Logger logger = LoggerFactory.getLogger(SchedulerUpdater.class);

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private SchedulerUpdateRepository schedulerUpdateRepository;

    @Override
    public void schedule(Job job) throws SchedulerException {
        List<Cron> crons = job.getCrons();
        if (CollectionUtils.isNotEmpty(crons)) {
            // ① **************** 创建任务触发器 实例列表 - 如果没有，则不进行添加
            Set<Trigger> triggers = buildTriggers(crons);
            // ② **************** 创建任务具体信息实例
            JobDetail jobDetail = buildJobDetail(job);
            job.setName(jobDetail.getKey().getName());
            // ③ **************** 添加任务
            scheduler.scheduleJob(jobDetail, triggers, true);
        } else {
            logger.error(" -- schedule job ：{} failed, cause :  no trigger available.",
                            job.getTitle());
        }
        schedulerUpdateRepository.save(job);
    }

    @Override
    public void schedule(List<Job> jobs) throws SchedulerException {
        Map<JobDetail, Set<? extends Trigger>> triggersAndJobs =
                        new HashMap<JobDetail, Set<? extends Trigger>>();
        for (Job job : jobs) {
            List<Cron> crons = job.getCrons();
            if (CollectionUtils.isNotEmpty(crons)) {
                // ① **************** 创建任务触发器 实例列表 - 如果没有，则不进行添加
                Set<Trigger> triggers = buildTriggers(crons);
                // ② **************** 创建任务具体信息实例
                JobDetail jobDetail = buildJobDetail(job);
                job.setName(jobDetail.getKey().getName());
                triggersAndJobs.put(jobDetail, triggers);
            } else {
                logger.error(" -- schedule job ：{} failed, cause :  no trigger available.",
                                job.getTitle());
            }
        }
        // ③ **************** 添加任务
        if (!triggersAndJobs.isEmpty()) {
            scheduler.scheduleJobs(triggersAndJobs, true);
            schedulerUpdateRepository.save(jobs);
        }
    }
    
    @Override
    public void reschedule(Job job) throws SchedulerException {
        List<Cron> crons = job.getCrons();
        if (CollectionUtils.isNotEmpty(crons)) {
            deleteJob(job.getName(), job.getGroup());
            schedule(job);
        } else {
            logger.error(" -- reschedule job ：{} failed, cause :  no trigger available.",
                            job.getTitle());
        }
    }

    /**
     * 构建任务详情(Quartz JobDetail).
     * 
     * @param job
     *            任务实体
     * @return JobDetail
     */
    private JobDetail buildJobDetail(Job job) {
        JobKey jobKey = jobKey(buildUniqueID(job.getGroup()), job.getGroup());
        JobDetail jobDetail = JobBuilder.newJob(BaseJob.class).withIdentity(jobKey).build();
        Map<String, Object> args = new HashMap<String, Object>(job.getArgs());
        args.put(JobConstant.JOB_BIZ_KEY, job.getBiz());
        args.put(JobConstant.JOB_TITLE_KEY, job.getTitle());
        jobDetail.getJobDataMap().putAll(args);
        return jobDetail;
    }

    /**
     * 构建任务触发器 (Quartz Trigger).
     * 
     * @param crons
     *            任务定时器
     * @return Trigger集合
     */
    private Set<Trigger> buildTriggers(List<Cron> crons) {
        Set<Trigger> triggers = new HashSet<Trigger>();
        CronScheduleBuilder scheduleBuilder = null;
        for (Cron cron : crons) {
            scheduleBuilder = cronSchedule(cron.getCron());
            TriggerKey triggerKey = triggerKey(buildUniqueID(cron.getGroup()), cron.getGroup());
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                .withSchedule(scheduleBuilder).build();
            triggers.add(trigger);
        }
        return triggers;
    }

    @Override
    public void triggerJob(String name, String group){
      SchedulerHelper.triggerJob(scheduler, name, group);
    }
    
    @Override
    public void pauseJob(String name, String group) {
        SchedulerHelper.pauseJob(scheduler, name, group);
    }

    @Override
    public void pauseJobs(String group) {
        SchedulerHelper.pauseJobs(scheduler, group);
    }

    @Override
    public void resumeJob(String name, String group) {
        SchedulerHelper.resumeJob(scheduler, name, group);
    }

    @Override
    public void resumeJobs(String group) {
        SchedulerHelper.resumeJobs(scheduler, group);
    }

    @Override
    public boolean deleteJob(String name, String group) {
        try {
            boolean rtn = SchedulerHelper.deleteJob(scheduler, name, group);
            logger.debug("删除 QRTZ 任务 ： {}" , rtn);
            schedulerUpdateRepository.delete(name, group);
            return true;
        } catch (Exception e) {
            logger.debug("删除 Task 失败： {}" , ExceptionUtils.getStackTrace(e));
            return false;
        }
    }

    @Override
    public boolean deleteJobs(String group) {
        try {
            boolean rtn = SchedulerHelper.deleteJobs(scheduler, group);
            logger.debug("删除 QRTZ 任务 ： {}" , rtn);
            schedulerUpdateRepository.delete(group);
            return true;
        } catch (Exception e) {
            logger.debug("删除 Task 失败： {}" , ExceptionUtils.getStackTrace(e));
            return false;
        }
    }

    @Override
    public void pauseTrigger(String name, String group) {
        SchedulerHelper.pauseTrigger(scheduler, name, group);
    }

    @Override
    public void pauseTriggers(String group) {
        SchedulerHelper.pauseTriggers(scheduler, group);
    }

    @Override
    public void resumeTrigger(String name, String group) {
        SchedulerHelper.resumeTrigger(scheduler, name, group);
    }

    @Override
    public void resumeTriggers(String group) {
        SchedulerHelper.resumeTriggers(scheduler, group);
    }

    @Override
    public boolean removeTrigger(String name, String group) {
        return SchedulerHelper.removeTrigger(scheduler, name, group);
    }

    @Override
    public boolean removeTriggers(String group) {
        return SchedulerHelper.removeTriggers(scheduler, group);
    }
}
